﻿using DefaultDspPluginsLib;
using DefaultDspPluginsLib.Depricated;
using SoundEngine3;
using System;
using System.Runtime.InteropServices;

namespace ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer.Engine.Modules.HighLevel
{
    /// <summary>
    /// LFO section of a modern synthesizer
    /// Low-frequency oscillation(LFO) is an electronic signal which is usually below 20 Hz and creates a rhythmic pulse or sweep.
    /// This pulse or sweep is often used to modulate synthesizers, delay lines and other audio equipment in order to create effects used in the production of electronic music.
    /// Audio effects such as vibrato, tremolo and phasing are examples.
    /// The abbreviation is also very often used to refer to low-frequency oscillators themselves.
    /// </summary>
    [ModuleDisplay("LFO")]
    public class LFOModule : BaseModule
    {
#if !Portable
        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern void Common_Modulizer_LFO_Process(int length, int waveformBufferLength, ref double currentSample, double sync, double sync_position, double tempo
            , double[] frequency, double[] amplitude, double[] amplitudeOffset
            , double[] waveForm, double[] output
            , double sampleRate);
#endif

        private double mCurrentSample = 0;

        public readonly ModuleOutput Output;

        public InputModuleParameter Frequency { get; private set; }

        public InputModuleParameter Amplitude { get; private set; }

        public InputModuleParameter AmplitudeOffset { get; private set; }

        public readonly ModuleInput InWaveform;

        /// <summary>
        /// If this value is non-off, this will be used instead of parameter Frequency.
        /// </summary>
        public InputModuleEnumParameter<FrequencySync> FrequencySyncer { get; private set; }

        public enum FrequencySync
        {
            Off = 0,
            _1of8 = 8000,
            _2of8 = 4000,
            _3of8 = 3000,
            _4of8 = 2000,
            _6of8 = 1500,
            _1 = 1000,
            _2of1 = 500,
            _3of1 = 330,
            _4of1 = 250,
            _8of1 = 125,
        }

        public LFOModule(ModuleManager manager)
            : base(manager)
        {
            AddOutput(Output = new ModuleOutput("Output", IOType.Audio, this));

            Frequency = new InputModuleParameter(this, "Freq", 10, IOType.Audio);
            Frequency.Label = "Frequency";
            Frequency.MinValue = 0.0;
            Frequency.MaxValue = 40.0;
            AddModuleParameter(Frequency);

            Amplitude = new InputModuleParameter(this, "Amp", 1, IOType.Audio);
            Amplitude.Label = "Amplitude";
            Amplitude.MinValue = 0.0;
            Amplitude.MaxValue = 1.0;
            AddModuleParameter(Amplitude);

            AmplitudeOffset = new InputModuleParameter(this, "AmpOf", 0, IOType.Audio);
            AmplitudeOffset.Label = "Amplitude offset";
            AmplitudeOffset.MinValue = -1.0;
            AmplitudeOffset.MaxValue = 1.0;
            AddModuleParameter(AmplitudeOffset);

            FrequencySyncer = new InputModuleEnumParameter<FrequencySync>(this, "Sync", 0, IOType.Audio);
            FrequencySyncer.Label = "Frequency Sync";
            AddModuleParameter(FrequencySyncer);

            InWaveform = new ModuleInput("Wav", "Waveform", IOType.Waveform, this);
            AddInput(InWaveform);
        }

        public override void Process()
        {
            ModuleOutput output = Output;

            //double sampleRate = 1.0 / SoundEngineContext.SampleRate;
            //double currentSample = mCurrentSample;
            double[] waveForm = InWaveform.IsConnected ? InWaveform.FromOutput.AudioBuffer.Buffer : null;

            double sync_position = SoundEngineContext.PPQ_To_Samples(SoundEngineContext.PpqPosition);
            if (NativeSoundEngineDllImport.UseNativeProcessing)
            {
#if !Portable
                Common_Modulizer_LFO_Process(output.AudioBuffer.Length, ModuleOutput.WAVEFORM_BUFFER_LENGTH, ref mCurrentSample, (double)FrequencySyncer.EnumValue,
                    sync_position, SoundEngineContext.Tempo,
                    Frequency.Values, Amplitude.Values, AmplitudeOffset.Values, waveForm, output.AudioBuffer.Buffer, SoundEngineContext.SampleRate);
#endif
            }
            else
            {
                Common_Modulizer_LFO.Process(output.AudioBuffer.Length, ModuleOutput.WAVEFORM_BUFFER_LENGTH, ref mCurrentSample, (double)FrequencySyncer.EnumValue,
                    sync_position, SoundEngineContext.Tempo,
                    Frequency.Values, Amplitude.Values, AmplitudeOffset.Values, waveForm, output.AudioBuffer.Buffer, SoundEngineContext.SampleRate);
            }
        }
    }
}
